/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvt-instruction */

#include <lkmc.h>

LKMC_PROLOGUE
    /* SIMD positive. */
.data
    vcvt_positive_0:      .float 1.25, 2.5, 3.75, 4.0
    vcvt_positive_expect: .word  1,    2,   3,    4
.bss
    vcvt_positive_result: .skip 0x10
.text
    ldr r0, =vcvt_positive_0
    vld1.32 {q0}, [r0]
    vcvt.u32.f32 q1, q0
    ldr r0, =vcvt_positive_result
    vst1.32 {q1}, [r0]
    LKMC_ASSERT_MEMCMP(vcvt_positive_result, vcvt_positive_expect, =0x10)

    /* SIMD negative. */
.data
    vcvt_negative_0:      .float -1.25, -2.5, -3.75, -4.0
    vcvt_negative_expect: .word  -1,    -2,   -3,    -4
.bss
    vcvt_negative_result: .skip 0x10
.text
    ldr r0, =vcvt_negative_0
    vld1.32 {q0}, [r0]
    vcvt.s32.f32 q1, q0
    ldr r0, =vcvt_negative_result
    vst1.32 {q1}, [r0]
    LKMC_ASSERT_MEMCMP(vcvt_negative_result, vcvt_negative_expect, =0x10)

    /* Floating point. */
.data
    vcvt_positive_float_0:      .float 1.5, 2.5
    vcvt_positive_float_expect: .word  1
                                .float      2.5
.bss
    vcvt_positive_float_result: .skip 0x8
.text
    ldr r0, =vcvt_positive_float_0
    vld1.32 {d0}, [r0]
    vcvt.u32.f32 s0, s0
    ldr r0, =vcvt_positive_float_result
    vst1.32 {d0}, [r0]
    LKMC_ASSERT_MEMCMP(vcvt_positive_float_result, vcvt_positive_float_expect, =0x8)

    /* Floating point but with immediates.
     *
     * You have to worry of course about representability of
     * the immediate in 4 bytes, which is even more fun for
     * floating point numbers :-)
     *
     * Doing this mostly to illustrate the joys of vmov.i32.
     *
     * For some reason, there is no vmov.i32 sn, only dn.
     * If you try to use sn, it does the same as .f32 and
     * stores a float instead. Horrible!
     */
    vmov.f32 d0, 1.5
    vcvt.u32.f32 s0, s0
    vmov.i32 d1, 1
    vcmp.f32 s0, s2
    vmrs apsr_nzcv, fpscr
    LKMC_ASSERT(beq)
    /* Check that s1 wasn't modified by vcvt. */
    vmov.f32 s2, 1.5
    vcmp.f32 s1, s2
    vmrs apsr_nzcv, fpscr
    LKMC_ASSERT(beq)

    /* Floating point double precision. */
.data
    vcvt_positive_double_0:      .double 1.5
    vcvt_positive_double_expect: .word   1
.bss
    vcvt_positive_double_result: .skip 0x8
.text
    ldr r0, =vcvt_positive_double_0
    vld1.64 {d0}, [r0]
    vcvt.u32.f64 s0, d0
    ldr r0, =vcvt_positive_double_result
    vst1.32 {d0}, [r0]
    LKMC_ASSERT_MEMCMP(
        vcvt_positive_double_result,
        vcvt_positive_double_expect,
        =0x4
    )
LKMC_EPILOGUE
